---
author: Marcus Rohrmoser
categories:
- en
- development
date: "2009-06-28T13:12:31+00:00"
tags:
- Cocoa
- compression
- gzip
- htaccess
- iPhone
- NSURLConnection
- Objective C
- wget
title: NSURLConnection gzip magic
type: post
url: /2009/06/nsurlconnection-gzip-magic/
yourls_shorturl:
- http://s.mro.name/2e
---
For quite some time I ranted about not being able to use compressed network communcation out-of-the-box on the iPhone.

Despite being undocumented (or I just overlooked the hint), [NSURLConnection][1] does [gzip][2] decompression transparently!

That's how to use it:

<!--more-->

1. ensure the webserver sends gzipped content, use e.g. [wget][3] to verify:
    <pre class="line-numbers"><code class="language-shell-session">$ wget --header='Accept-Encoding: gzip' \
        --server-response http://example.com/demo.xmlz
    </code></pre>
    It should (in case of a gzipped xml document) look like
    <pre class="line-numbers"><code class="language-log">HTTP/1.1 200 OK
    ...
    Content-Type: text/xml
    Content-Encoding: gzip
    ...
    </code></pre>

2. If your webserver doesn't support transparent compression, you can still upload gzipped content and tell the server to send the correct response headers by setting up a [.htaccess][4] file:

    <pre class="line-numbers"><code class="language-apacheconf">...
    AddType text/xml .xml .xmlz
    AddEncoding gzip .gz .xmlz

    # inspired by
    # http://betterexplained.com/articles/
    #  how-to-optimize-your-site-with-gzip-compression/
    # compress all text & html:
    AddOutputFilterByType DEFLATE text/html text/plain text/xml
    ...
    </code></pre>
3. to verify from within your app, log the response header in the NSURLConnection callbacks:

    <pre class="line-numbers"><code class="language-objc">- (void)connection:(NSURLConnection *)connection
      didReceiveResponse:(NSURLResponse *)response
    {
        NSLog(@"didReceiveResponse %@: %@", [response URL],
    [(NSHTTPURLResponse*)response allHeaderFields]);
        buffer = [[NSMutableData dataWithCapacity:1024*1024] retain];
    }
    
    - (void)connection:(NSURLConnection *)connection
      didReceiveData:(NSData *)dat
    {
        [buffer appendData:dat];
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection *)connection
    {
        NSLog(@"connectionDidFinishLoading %d bytes", [buffer length]);
        [buffer release];
    }
    </code></pre>

    It should look like

    <pre class="line-numbers"><code class="language-log">2009-06-28 14:31:09.722 DemoApp[3981:20b] \
      didReceiveResponse http://example.com/demo.xmlz: {
    ...
    "Content-Type" = "text/xml";
    "Content-Encoding" = gzip;
    "Content-Length" = 123042;
    }
    ...
    2009-06-28 14:31:11.619 DemoApp[3981:20b] \
      connectionDidFinishLoading 602979 bytes
    </code></pre>

   As you can see we received way more bytes than went over the wire.

* enjoy lightning fast network communication!

P.S.: It seems not to be necessary setting the request header yourself:

<pre class="line-numbers"><code class="language-objc">NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
    cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
    timeoutInterval:60.0];
// set explicitly:
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
</code></pre>

 [1]: http://developer.apple.com/documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
 [2]: http://en.wikipedia.org/wiki/Gzip
 [3]: http://www.gnu.org/software/wget/
 [4]: http://en.wikipedia.org/wiki/Htaccess
